/**
 *  Promise.all()
 */
const p1 = Promise.resolve('p1')

const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2 延时一秒')
    }, 1000)
})

const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p3 延时两秒')
    }, 2000)
})
const p4 = Promise.reject('p4 rejected')

const p5 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('p5 rejected 延时1.5秒')
    }, 1500)
})

Promise.MyAll = function (promises) {
    let arr = [];
    let count = 0;
    return new Promise((resolve, reject) => {
        promises.forEach((item, i) => {
            Promise.resolve(item).then((res) => { // 需要用resolve，将promises数组中不是promise的转化成promise， 也会有将状态为pending的promise转化成resolve状态再调用.then 如 p = new Promise((resolve,reject)=>{ })
                arr[i] = res;                 // 使用数组确保promise数组的参数和promise的状态改变的回调函数的返回值一一对应
                count = count + 1;
                if (count == promises.length)
                    resolve(arr);
            }).catch(reject)
        })
    })
}

// 所有Promise实例都成功,才会返回
Promise.MyAll([p1, p2, p3])
    .then(res => {
        console.log(res)
    })
    .catch(err => console.log(err)) // 2秒后打印 [ 'p1', 'p2 延时一秒', 'p3 延时两秒' ]



Promise.MyAll2 = function (promises) {
    let arr = [],
        count = 0
    return new Promise((resolve, reject) => {
        promises.forEach((item, i) => {
            Promise.resolve(item).then(res => {
                arr[i] = res
                count += 1
                if (count === promises.length) resolve(arr)
            }, reject)  // 第二个参数reject
        })
    })
}


Promise.MyRace = function (promises) {
    return new Promise((resolve, reject) => {
        // Promise.race 不需要像promise.all 一样一一对应，只需要返回最快的哪一个
        for (const item of promises) {
            return item.resolve().then(resolve, reject);
        }
    })
}


Promise.MyAny = function (promises) {
    let arr = [];
    let count = 0;
    return new Promise((resolve, reject) => {
        // Promise.race 不需要像promise.all 一样一一对应，只需要返回最快的哪一个
        promises.forEach((item, i) => {
            Promise.resolve(item).then(resolve, (err) => { // 与Promise.all 思路相反，保存错误的数组，当数组个数到达传参到达pomises.length参数个数时候返回
                arr[i] = { status: 'rejected', val: 'err' }
                count++;
                if (count === promises.length)
                    reject(new Error('所有promiseall出错'))
            })
        })
    })
}

// Promise.allSettled 无论成功与否都会返回成功，并生成状态数组，无论数组里面的promise是resolve还说reject，都应该变为resolve输出出来，只不过需要根据resolve还是reject改变status
// 并且跟Promise.all一样，返回值的位置对应传参的位置，所以需要用 forEach((item,i))
//  [
//   { status: 'rejected', reason: 'p4 rejected' },
//   { status: 'rejected', reason: 'p5 rejected 延时1.5秒' }
// ]
// 思路：是promise.all 和 promise.any的结合，一边需要resolve的返回，还需要reject的返回，当数量满足，调用resolve改变状态返回出来。
Promise.MyallSettled = function (promises) {
    return new Promise((resolve, reject) => {
        let arr = [], count = 0;
        promises.forEach((item, i) => {
            Promise.resolve(item).then((res) => { // 需要用resolve，将promises数组中不是promise的转化成promise， 也会有将状态为pending的promise转化成resolve状态再调用.then 如 p = new Promise((resolve,reject)=>{ })

                arr[i] = { status: 'fulfilled', val: res }              // 使用数组确保promise数组的参数和promise的状态改变的回调函数的返回值一一对应
                count = count + 1;
                if (count === promises.length)
                    resolve(arr);
            }, (err) => {

                arr[i] = { status: 'rejected', val: err }
                count = count + 1;
                if (count === promises.length)
                    resolve(arr);
            })
        })
    })
}

// Promise.MyallSettled([p1, p2, p3]).then(res => console.log(res))


// 进行优化封装，DRY 原则不写重复代码
Promise.MyAllSettled2 = function (promises) {
    let arr = [],
        count = 0
    return new Promise((resolve, reject) => {
        const processResult = (res, index, status) => {
            arr[index] = { status: status, val: res }
            count += 1
            if (count === promises.length) resolve(arr)
        }

        promises.forEach((item, i) => {
            Promise.resolve(item).then(res => {
                processResult(res, i, 'fulfilled')
            }, err => {
                processResult(err, i, 'rejected')
            })
        })
    })
}

